package io.github.ali.commons.code;

import io.github.ali.commons.exception.BizException;
import io.github.ali.commons.exception.BizRuntimeException;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author ALi
 * @version 1.0
 * @date 2021-10-15 14:20
 * @description
 */
public abstract class AbstractExceptionCode implements ExceptionCode, Supplier<RuntimeException>, Function<Object,RuntimeException> {
	/**
	 * 错误码(内部码)
	 */
	public final String errorCode;
	/**
	 * 错误信息
	 */
	public final String errorMsg;
	/**
	 * 响应码(外部码)
	 */
	public final RespCode respCode;

	protected AbstractExceptionCode(String errorCode, String errorMsg, RespCode respCode) {
		this.errorCode = errorCode;
		this.errorMsg = errorMsg;
		this.respCode = respCode;
		fillDefaultCode();
	}

	protected AbstractExceptionCode(String errorCode, RespCode respCode) {
		this.errorCode = errorCode;
		this.errorMsg = respCode.getMessage();
		this.respCode = respCode;
		fillDefaultCode();
	}
	private void fillDefaultCode() {
		if (AbstractExceptionCode.FAILED == null) {
			AbstractExceptionCode.FAILED = getFailed();
		}
	}

	@Override
	public String getErrorCode() {
		return errorCode;
	}

	@Override
	public String getErrorMsg() {
		return errorMsg;
	}

	@Override
	public RespCode getRespCode() {
		return respCode;
	}

	@Override
	public RuntimeException get() {
		return buildBizRuntimeException();
	}

	@Override
	public RuntimeException apply(Object o) {
		if (o == null) {
			return buildBizRuntimeException();
		}
		if (o instanceof Throwable) {
			return buildBizRuntimeException((Throwable) o);
		}
		return buildBizRuntimeException(o.toString());
	}

	@Override
	public BizRuntimeException buildBizRuntimeException() {
		BizRuntimeException exception = RUNTIMEEXCEPTIONS.get(this);
		if (exception == null) {
			exception = new BizRuntimeException(this);
			RUNTIMEEXCEPTIONS.put(this, exception);
		}
		return exception;
	}
	@Override
	public BizRuntimeException buildBizRuntimeException(String message) {
		return new BizRuntimeException(this, message);
	}

	@Override
	public BizRuntimeException buildBizRuntimeException(Throwable cause) {
		return new BizRuntimeException(this, cause);
	}

	@Override
	public BizRuntimeException buildBizRuntimeException(Throwable cause, String message) {
		return new BizRuntimeException(this, cause, message);
	}

	@Override
	public BizException buildBizException() {
		BizException exception = EXCEPTIONS.get(this);
		if (exception == null) {
			exception = new BizException(this);
			EXCEPTIONS.put(this, exception);
		}
		return exception;
	}

	@Override
	public BizException buildBizException(String message) {
		return new BizException(this, message);
	}

	@Override
	public BizException buildBizException(Throwable cause) {
		return new BizException(this, cause);
	}

	@Override
	public BizException buildBizException(Throwable cause, String message) {
		return new BizException(this, cause, message);
	}

	/**
	 * 返回默认异常码
	 * 由子类自定义默认异常码
	 * @return
	 */
	protected abstract ExceptionCode getFailed();

	private static Map<ExceptionCode, BizException> EXCEPTIONS = new HashMap<ExceptionCode, BizException>();
	private static Map<ExceptionCode, BizRuntimeException> RUNTIMEEXCEPTIONS = new HashMap<ExceptionCode, BizRuntimeException>();
	private static ExceptionCode FAILED;

	/**
	 * 获取默认异常码
	 * 若未自定义ExceptionCode则返回空
	 * @return
	 */
	public static ExceptionCode getDefaultExceptionCode(){
		return FAILED;
	}
}
